package com.etl.es.service;

import com.etl.es.document.FilmDocument;
import com.etl.es.repository.FilmRepository;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * ES电影服务
 *
 * @author: chenfenghai
 * @version: 1.0
 * @date: 2020-10-29 14:51
 */
@Slf4j
@Service
public class FilmService {

    @Autowired
    FilmRepository filmRepository;

    /**
     * 缓存电影信息，Guava cache
     */
    private static LoadingCache<String, Optional<FilmDocument>> cache;

    /**
     * 初始化缓存，并设置失效时间
     */
    @PostConstruct
    private void initCache() {
        cache = CacheBuilder.newBuilder()
                .expireAfterAccess(1, TimeUnit.HOURS)
                .build(new CacheLoader<String, Optional<FilmDocument>>() {
                    @Override
                    public Optional<FilmDocument> load(String id) {
                        return filmRepository.findById(id);
                    }
                });
    }

    /**
     * 建造电影文档
     *
     * @param filmCode 电影编码
     * @param filmName 电影名称
     * @return FilmDocument
     */
    public FilmDocument buildFilmDocument(String filmCode, String filmName) {
        // 处理异常数据，如果电影编码为空，则返回空的文档实体
        if (Objects.isNull(filmCode)) {
            return FilmDocument.builder().build();
        }
        FilmDocument filmDocument = FilmDocument.builder()
                .filmCode(filmCode)
                .filmName(filmName)
                .build();
        // 如果缓存中存在，则直接从缓存中返回
        // 如果缓存中不存在，则从ES中查询返回，并默认存放到缓存中
        // 如果缓存中不存在，并且ES中也不存在，则PUT到缓存中并且保存到ES中，再返回
        try {
            return cache.getUnchecked(filmCode).orElseGet(() -> {
                cache.put(filmCode, Optional.of(filmDocument));
                return filmRepository.save(filmDocument);
            });
        } catch (Exception e) {
            log.error("Used LoadingCache Exception", e);
            // 缓存异常也保存到ES
            filmRepository.save(filmDocument);
        }
        return filmDocument;
    }
}
